import { Injectable } from '@nestjs/common'
import { JwtService } from '@nestjs/jwt'
import { InjectRepository } from '@nestjs/typeorm'
import { LOGIN_TOKEN_EXPIRESIN } from 'src/common/constant'
import { CacheEnum, DataScopeEnum, DelFlagEnum, StatusEnum } from 'src/common/enum'
import { GenerateUUID, GetNowDate } from 'src/common/utils'
import { ResultData } from 'src/common/utils/result'
import { ClientInfoDto, LoginDto } from 'src/modules/main/dto'
import { RedisService } from 'src/modules/redis/redis.service'
import { In, Repository } from 'typeorm'
import { DeptService } from '../dept/dept.service'
import { SysDeptEntity } from '../dept/entities/dept.entity'
import { SysPostEntity } from '../post/entities/post.entity'
import { RoleService } from '../role/role.service'
import { ListUserDto } from './dto'
import { UserEntity } from './entities/sys-user-entity'
import { SysUserWithPostEntity } from './entities/user-width-post.entity'
import { SysUserWithRoleEntity } from './entities/user-width-role.entity'

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepo: Repository<UserEntity>,
    @InjectRepository(SysUserWithRoleEntity)
    private readonly sysUserWithRoleEntityRep: Repository<SysUserWithRoleEntity>,
    @InjectRepository(SysUserWithPostEntity)
    private readonly sysUserWithPostEntityRep: Repository<SysUserWithPostEntity>,
    @InjectRepository(SysPostEntity)
    private readonly sysPostEntityRep: Repository<SysPostEntity>,
    @InjectRepository(SysDeptEntity)
    private readonly sysDeptEntityRep: Repository<SysDeptEntity>,
    private readonly jwtService: JwtService,
    private readonly roleService: RoleService,
    private readonly redisService: RedisService,
    private readonly deptService: DeptService
  ) {}
  /**
   * 从令牌中获取数据声明
   *
   * @param token 令牌
   * @return 数据声明
   */
  parseToken(token: string) {
    try {
      if (!token) return null
      const payload = this.jwtService.verify(token.replace('Bearer ', ''))
      return payload
    } catch (error) {
      return null
    }
  }
  /**
   * 从数据声明生成令牌
   *
   * @param payload 数据声明
   * @return 令牌
   */
  createToken(payload: { uuid: string; userId: number }): string {
    const accessToken = this.jwtService.sign(payload)
    return accessToken
  }
  /**
   * 用户登录接口
   */
  async login(user: LoginDto, clientInfo: ClientInfoDto) {
    const data = await this.userRepo.findOne({
      where: {
        userName: user.username,
        password: user.password
      },
      select: ['userId']
    })
    if (!data) {
      return ResultData.fail(500, `帐号或密码错误`)
    }
    const userData = await this.getUserinfo(data.userId)
    if (userData.delFlag === DelFlagEnum.DELETE) {
      return ResultData.fail(500, '您已被禁用，如需正常使用请联系管理员')
    }
    if (userData.status === StatusEnum.STOP) {
      return ResultData.fail(500, '您已被停用，如需正常使用请联系管理员')
    }
    const uuid = GenerateUUID()
    const token = this.createToken({ uuid, userId: userData.userId })
    const permissions = ['*:*:*']
    const deptData = await this.sysDeptEntityRep.findOne({
      where: {
        deptId: userData.deptId
      },
      select: ['deptName']
    })
    userData['deptName'] = deptData.deptName || ''
    const loginTime = GetNowDate()
    const cacheData = {
      browser: clientInfo.browser,
      ipaddr: clientInfo.ipaddr,
      loginLocation: clientInfo.loginLocation,
      loginTime: loginTime,
      os: clientInfo.os,
      permissions: permissions,
      token: uuid,
      user: userData,
      userId: userData.userId,
      username: userData.userName,
      deptId: userData.deptId
    }
    this.redisService.set(`${CacheEnum.LOGIN_TOKEN_KEY}${uuid}`, cacheData, LOGIN_TOKEN_EXPIRESIN)
    return ResultData.ok({ token }, '登录成功')
  }
  /**
   * 获取角色Id列表
   * @param userId
   * @returns
   */
  async getRoleIds(userIds: Array<number>) {
    const roleList = await this.sysUserWithRoleEntityRep.find({
      where: {
        userId: In(userIds)
      },
      select: ['roleId']
    })
    const roleIds = roleList.map((item) => Number(item.roleId))
    return roleIds
  }
  /**
   * 获取用户信息
   */
  async getUserinfo(userId: number) {
    const entity = this.userRepo.createQueryBuilder('user')
    entity.where({
      userId: userId,
      delFlag: DelFlagEnum.NORMAL
    })
    // 联查部门详情, 查到用户的部门信息
    entity.leftJoinAndMapOne('user.dept', SysDeptEntity, 'dept', 'dept.deptId = user.deptId')
    const roleIds = await this.getRoleIds([userId])
    // 查询角色信息
    const roles = await this.roleService.findRoles({
      where: {
        delFlag: DelFlagEnum.NORMAL,
        roleId: In(roleIds)
      }
    })
    // 查询岗位 id
    const postIds = (
      await this.sysUserWithPostEntityRep.find({
        where: {
          userId: userId
        },
        select: ['postId']
      })
    ).map((item) => item.postId)

    // 查询岗位名称
    const posts = await this.sysPostEntityRep.find({
      where: {
        postId: In(postIds),
        delFlag: DelFlagEnum.NORMAL
      }
    })
    const resData = await entity.getOne()
    resData['roles'] = roles
    resData['posts'] = posts
    return resData
  }

  /**
   * @description 获取用户列表
   */
  async findAll(query: ListUserDto, user: any) {
    const entity = this.userRepo.createQueryBuilder('user')
    entity.where('user.delFlag = :delFlag', { delFlag: '0' })

    // 数据权限过滤
    if (user) {
      const roles = user.roles
      const deptIds = []
      let role = undefined
      let dataScopeAll = false
      let dataScopeSelf = false
      for (let index = 0; index < roles.length; index++) {
        role = roles[index]
        if (role.dataScope === DataScopeEnum.DATA_SCOPE_ALL) {
          dataScopeAll = true
          break
        } else if (role.dataScope === DataScopeEnum.DATA_SCOPE_CUSTOM) {
          const roleWithDeptIds = await this.roleService.findRoleWithDeptIds(role.roleId)
          deptIds.push(...roleWithDeptIds)
        } else if (
          role.dataScope === DataScopeEnum.DATA_SCOPE_DEPT ||
          role.dataScope === DataScopeEnum.DATA_SCOPE_DEPT_AND_CHILD
        ) {
          const dataScopeWidthDeptIds = await this.deptService.findDeptIdsByDataScope(
            user.deptId,
            role.dataScope
          )
          deptIds.push(...dataScopeWidthDeptIds)
        } else if (role.dataScope === DataScopeEnum.DATA_SCOPE_SELF) {
          dataScopeSelf = true
        }
      }
      if (dataScopeAll) {
        if (deptIds.length > 0) {
          entity.where('user.deptId IN (:...deptIds)', { deptIds: deptIds })
        } else if (dataScopeSelf) {
          entity.where('user.userId = :userId', { userId: user.userId })
        }
      }
    }
    if (query.deptId) {
      const deptIds = await this.deptService.findDeptIdsByDataScope(
        +query.deptId,
        DataScopeEnum.DATA_SCOPE_DEPT_AND_CHILD
      )
      entity.andWhere('user.deptId IN (:...deptIds)', { deptIds: deptIds })
    }

    if (query.userName) {
      entity.andWhere(`user.userName LIKE "%${query.userName}%"`)
    }

    if (query.phonenumber) {
      entity.andWhere(`user.phonenumber LIKE "%${query.phonenumber}%"`)
    }

    if (query.status) {
      entity.andWhere('user.status = :status', { status: query.status })
    }

    if (query.params?.beginTime && query.params?.endTime) {
      entity.andWhere('user.createTime BETWEEN :start AND :end', {
        start: query.params.beginTime,
        end: query.params.endTime
      })
    }
    entity.skip(query.pageSize * (query.pageNum - 1)).take(query.pageSize)
    // 联查部门详情
    entity.leftJoinAndMapOne('user.dept', SysDeptEntity, 'dept', 'dept.deptId = user.deptId')
    const [list, total] = await entity.getManyAndCount()

    return ResultData.ok({
      list,
      total
    })
  }
}
